<template>
    <div class="chat-container">
      <!-- 登录状态 -->
      <div v-if="!isConnected" class="login-box">
        <h2>欢迎进入聊天室</h2>
        <div class="input-group">
          <el-input
            v-model.trim="user"
            placeholder="请输入用户名"
            @keyup.enter="handleLogin"
            maxlength="20"
            show-word-limit
          >
            <template #prefix>
              <el-icon><User /></el-icon>
            </template>
          </el-input>
          <el-button 
            type="primary" 
            @click="handleLogin"
            :disabled="!isValidUser"
            :loading="isConnecting"
          >
            {{ isConnecting ? '连接中...' : '开始聊天' }}
          </el-button>
        </div>
      </div>
  
      <!-- 聊天界面 -->
      <div v-else class="chat-main">
        <!-- 消息展示区 -->
        <div class="message-list" ref="messageList">
          <div 
            v-for="(msg, index) in messages" 
            :key="index" 
            class="message-item"
            :class="{ 'own-message': msg.user === user }"
          >
            <div class="message-header">
              <el-avatar :size="24" :src="msg.avatar || defaultAvatar" />
              <span class="username">{{ msg.user }}</span>
              <span class="timestamp">{{ formatTime(msg.timestamp) }}</span>
            </div>
            <div class="message-content" v-html="sanitize(msg.content)"></div>
          </div>
        </div>
  
        <!-- 消息发送区 -->
        <div class="message-input">
          <el-input
            v-model.trim="message"
            type="textarea"
            :rows="2"
            resize="none"
            placeholder="输入消息..."
            @keyup.enter.native="handleSend"
            :disabled="!isConnected"
          >
            <template #append>
              <el-button 
                type="primary" 
                @click="handleSend"
                :disabled="!isValidMessage"
              >
                发送
              </el-button>
            </template>
          </el-input>
        </div>
      </div>
  
      <!-- 连接状态提示 -->
      <el-dialog
        v-model="showReconnect"
        title="连接已断开"
        width="30%"
        :close-on-click-modal="false"
        :show-close="false"
      >
        <span>正在尝试重新连接...({{ reconnectCount }}/5)</span>
      </el-dialog>
    </div>
  </template>
  
  <script>
  import { ref, computed, onBeforeUnmount, nextTick } from 'vue'
  import { User } from '@element-plus/icons-vue'
  import { ElMessage } from 'element-plus'
  import DOMPurify from 'dompurify'
  
  export default {
    setup() {
      // 响应式数据
      const user = ref('')
      const message = ref('')
      const messages = ref([])
      const ws = ref(null)
      const isConnecting = ref(false)
      const reconnectCount = ref(0)
      const showReconnect = ref(false)
      const messageList = ref(null)
      const heartbeatInterval = ref(null)
      const reconnectTimer = ref(null)
      const defaultAvatar = 'https://example.com/default-avatar.png'
  
      // 计算属性
      const isValidUser = computed(() => user.value.length >= 3)
      const isValidMessage = computed(() => message.value.trim().length > 0)
      const isConnected = computed(() => ws.value?.readyState === WebSocket.OPEN)
  
      // 生命周期
      onBeforeUnmount(() => {
        closeConnection()
        clearTimers()
      })
  
      // 方法
      const initWebSocket = () => {
        closeConnection()
        isConnecting.value = true
  
        ws.value = new WebSocket(`ws://${location.host}/ws/${user.value}`)
  
        ws.value.onopen = () => {
          isConnecting.value = false
          reconnectCount.value = 0
          startHeartbeat()
          ElMessage.success('连接成功')
        }
  
        ws.value.onmessage = (event) => {
          const data = JSON.parse(event.data)
          if (data.type === 'heartbeat') return
          messages.value.push(data)
          scrollToBottom()
        }
  
        ws.value.onerror = (error) => {
          console.error('WebSocket错误:', error)
          handleReconnect()
        }
  
        ws.value.onclose = (event) => {
          if (!event.wasClean) {
            handleReconnect()
          }
        }
      }
  
      const handleLogin = async () => {
        if (!isValidUser.value) return
        try {
          await initWebSocket()
        } catch (error) {
          ElMessage.error('连接失败')
          handleReconnect()
        }
      }
  
      const handleSend = () => {
        if (!isValidMessage.value || !isConnected.value) return
        
        const msg = {
          user: user.value,
          content: message.value,
          timestamp: Date.now()
        }
  
        ws.value.send(JSON.stringify(msg))
        message.value = ''
      }
  
      const handleReconnect = () => {
        if (reconnectCount.value >= 5) {
          ElMessage.warning('重连失败，请检查网络')
          return
        }
  
        showReconnect.value = true
        reconnectCount.value++
  
        clearTimeout(reconnectTimer.value)
        reconnectTimer.value = setTimeout(() => {
          initWebSocket()
        }, Math.min(1000 * 2 ** reconnectCount.value, 10000))
      }
  
      const startHeartbeat = () => {
        clearInterval(heartbeatInterval.value)
        heartbeatInterval.value = setInterval(() => {
          if (isConnected.value) {
            ws.value.send(JSON.stringify({ type: 'heartbeat' }))
          }
        }, 30000)
      }
  
      const closeConnection = () => {
        if (ws.value) {
          ws.value.close(1000, '用户主动断开')
          ws.value = null
        }
      }
  
      const clearTimers = () => {
        clearInterval(heartbeatInterval.value)
        clearTimeout(reconnectTimer.value)
      }
  
      const scrollToBottom = () => {
        nextTick(() => {
          if (messageList.value) {
            messageList.value.scrollTop = messageList.value.scrollHeight
          }
        })
      }
  
      const formatTime = (timestamp) => {
        return new Date(timestamp).toLocaleTimeString()
      }
  
      const sanitize = (html) => {
        return DOMPurify.sanitize(html)
      }
  
      return {
        user,
        message,
        messages,
        isConnected,
        isConnecting,
        reconnectCount,
        showReconnect,
        messageList,
        defaultAvatar,
        isValidUser,
        isValidMessage,
        handleLogin,
        handleSend,
        formatTime,
        sanitize
      }
    }
  }
  </script>
  
  <style scoped>
  .chat-container {
    max-width: 800px;
    margin: 0 auto;
    height: 100vh;
    display: flex;
    flex-direction: column;
  }
  
  .login-box {
    padding: 2rem;
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.1);
  }
  
  .input-group {
    display: grid;
    gap: 1rem;
  }
  
  .message-list {
    flex: 1;
    overflow-y: auto;
    padding: 1rem;
    background: #f8f9fa;
  }
  
  .message-item {
    margin-bottom: 1rem;
    padding: 0.8rem;
    background: #fff;
    border-radius: 4px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  }
  
  .own-message {
    background: #e3f2fd;
    margin-left: 20%;
  }
  
  .message-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
  }
  
  .username {
    font-weight: 500;
  }
  
  .timestamp {
    font-size: 0.8rem;
    color: #666;
  }
  
  .message-content {
    word-break: break-word;
    line-height: 1.5;
  }
  
  .message-input {
    padding: 1rem;
    background: #fff;
    border-top: 1px solid #eee;
  }
  </style>